import argot
from argot import TypeName
from bookstore.BookNotFoundException import BookNotFoundException

class Bookstore (object):
    def __init__(self):
        self.books = []
        self.isbnMap = {}
        
    def loadBooks(self, filename):  
        """
         The load books provides a very basic example of how the Argot
         TypeInputStream is used.  
         
         A booklist type is red from the selected filename.
        """
        f = open(filename, 'rb')

        # Create a map of data types required for this file.
        typeMap = self.getDataFileTypeMap()

        def reader(size):
            #print 'reading %d bytes' % size
            return f.read(size)
            
        # Create a typed input stream using file and type map.
        typeInputStream = argot.TypeInputStream( typeMap, reader )
        
        # The file structure is defined by booklist.  Read the books.
        #print 'Reading booklist'
        typeInputStream.read_named_object( TypeName("booklist") )
        #print 'Done'
        books = argot.py_convert_to_python_object(typeInputStream.stack.ptr)
        #print books

        for book in books:
            self.addBook( book )


    def saveBooks(self, filename):
        """
         The save books method is the exact reverse of the read books.
         An array of books is passed to Argot to be written to file.
        """
        f = open(filename, 'wb')
        def outputStream(buffer):
            #print 'writing %d bytes' % len(buffer)
            f.write(buffer)
            f.flush()
            return len(buffer)
        
        typeMap = self.getDataFileTypeMap()
        typeOutputStream = argot.TypeOutputStream( typeMap, outputStream )
        typeOutputStream.write_named_object( TypeName("booklist"), self.getAllBooks() )

    def getDataFileTypeMap(self):    
        """
         The TypeMap is a central concept to Argot.  It maps selected
         data types from the internal system to the external system.
         In this case only a small number of data types is used in the 
         external data file used to store the book list. 
        """
        library = argot.TypeLibrarySingleton.getDefault()
        map = argot.TypeMap( library )
        map.map( 1, library.get_id( TypeName("book") ) )
        map.map( 2, library.get_id( TypeName("booklist") ))
        map.map( 3, library.get_id( TypeName("u8ascii") ))
        map.map( 4, library.get_id( TypeName("u8") ))
        return map


    # The rest of the bookstore implementation follows.
    def addBook(self, book):
        try:
            bookCheck = self.isbnMap[ book.ISBN ]
            return False
        except KeyError:
            pass
            
        self.isbnMap[ book.ISBN ] = book
        self.books.append( book )
        return True
    
    def removeBook( self, isbn ):
        book = self.getBookByIsbn(isbn)
        self.books.remove(book)
        del self.isbnMap[ isbn ]
    
    def findBooksByAuthor( self, name ):
        return [book for book in self.books if book.author == name]
    
    def getBookByIsbn( self, isbn ):
        try:
            book = self.isbnMap[ isbn ]
        except KeyError:
            raise BookNotFoundException( isbn )

        return book
    
    def getAllBooks( self ):
        return self.books
